package com.chhuang.utils.file;

import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;

import javax.imageio.ImageIO;

import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeManager;

import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;
/**
 * 
 * @author 黄晨
 *
 */
public class OpenOfficeUtil {
	private OpenOfficeUtil(){}
	
	private static final String PDF = ".pdf";
	private static final String JPG = ".jpg";
	private static  OfficeManager officeManager;
	private static String ooh = "" ;// 这里是OpenOffice的安装目录,
	private static int[] oop = new int[]{8100};//openoffice端口号,默认为8100
	
	/**
	 * 初始化OpenOffice的安装目录和openoffice端口号
	 * @param openOfficeHome
	 * @param openOfficePort
	 */
	public static void init(String openOfficeHome,Integer openOfficePort){
		ooh = openOfficeHome;
		oop[0] = openOfficePort;
	}
	
	/**
	 * 初始化OpenOffice的安装目录,openoffice端口号默认为8100
	 * @param openOfficeHome
	 */
	public static void init(String openOfficeHome){
		ooh = openOfficeHome;
	}
	
	/**
	 * 打开打开openoffice服务，需要先调用init()方法设置openOffice安装目录和和端口号
	 */
	public static void startOpenOfficeService() {
		DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
		try {
			configuration.setOfficeHome(ooh);// 设置OpenOffice.org安装目录
			configuration.setPortNumbers(oop); // 设置转换端口，默认为8100
			configuration.setTaskExecutionTimeout(1000 * 60 * 10L);// 设置任务执行超时为10分钟
			configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);// 设置任务队列超时为24小时

			officeManager = configuration.buildOfficeManager();
			officeManager.start(); // 启动服务
		} catch (Exception ce) {
			ce.printStackTrace();
		}
	}
	/**
	 * 使用后，关闭openoffice服务
	 */
	public static void stopOpenOfficeService(){
		if (officeManager != null) {
            officeManager.stop();
        }
	}
	
	/**
	 * 把sourceFile文档转成pdf和第一页的jpg缩略图放destDir目录下
	 * @param sourceFile
	 * @param destDir
	 */
	public static void transformFile(String sourceFile, String destDir, double outputWidth,double outputHeight){
		String filename = sourceFile.substring(sourceFile.lastIndexOf(File.separator)+1, sourceFile.lastIndexOf("."));
		String suffix = sourceFile.substring(sourceFile.lastIndexOf("."));
		if (destDir.charAt(destDir.length() - 1) != '/') {
			destDir += File.separator;
		}
		if(!suffix.equalsIgnoreCase(PDF)){
			OpenOfficeUtil.office2PDF(sourceFile,destDir+filename+PDF);
		}
		OpenOfficeUtil.pdf2Image(destDir+filename+PDF,destDir+filename+JPG, outputWidth, outputHeight);
	}
	
	/**
	 * office转pdf
	 * @param sourceFile
	 * @param destFile
	 * @return
	 */
	public static boolean office2PDF(String sourceFile, String destFile) {
		boolean result = false;
		File inputFile = new File(sourceFile);
		if (!inputFile.exists()) {
			return result;// 找不到源文件
		}
		// 如果目标路径不存在, 则新建该路径
		File outputFile = new File(destFile);
		if (!outputFile.getParentFile().exists()) {
			outputFile.getParentFile().mkdirs();
		}
		OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager);
		converter.convert(inputFile, outputFile);
		result=true;
		return result;
	}
	
	/**
	 * pdf第一页转jpg缩略图
	 * @param sourceFile
	 * @param destFile
	 * @throws IOException
	 */
	public static boolean pdf2Image(String sourceFile, String destFile,double outputWidth,double outputHeight) {
		boolean result = false;
		try{
			// load a pdf from a byte buffer
			File inputFile = new File(sourceFile);
			if (!inputFile.exists()) {
				return result;// 找不到源文件
			}
			RandomAccessFile raf = new RandomAccessFile(inputFile, "r");
			FileChannel channel = raf.getChannel();
			//这句代码通道建立了map映射,如果要删除file那么得接触映射
			ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0,channel.size());
			PDFFile pdffile = new PDFFile(buf);
			int totalpage = pdffile.getNumPages();
			for (int i = 1; i <= totalpage; i++) {
				if (i == 1) {
					// draw the first page to an image
					// 以图片的形式来描绘首页
					PDFPage page = pdffile.getPage(i);
					Rectangle rect = new Rectangle(0, 0, (int) page.getBBox()
							.getWidth(), (int) page.getBBox().getHeight());
					// generate the image
					// 生成图片
					Image img = page.getImage(rect.width, rect.height, // width &
							// height
							rect, // clip rect
							null, // null for the ImageObserver
							true, // fill background with white
							true // block until drawing is done
							);
					
					int newWidth;
					int newHeight;
					// 为等比缩放计算输出的图片宽度及高度
					double rate1 = ((double) img.getWidth(null)) / (double) outputWidth + 0.1;
					double rate2 = ((double) img.getHeight(null)) / (double) outputHeight + 0.1;
					// 根据缩放比率大的进行缩放控制
					double rate = rate1 > rate2 ? rate1 : rate2;
					newWidth = (int) (((double) img.getWidth(null)) / rate);
					newHeight = (int) (((double) img.getHeight(null)) / rate);
					
					BufferedImage tag = new BufferedImage(newWidth, newHeight,
							BufferedImage.TYPE_INT_RGB);
					tag.getGraphics().drawImage(
							img.getScaledInstance(newWidth, newHeight,
									Image.SCALE_SMOOTH), 0, 0, null);
					File outputFile = new File(destFile);
					if (!outputFile.getParentFile().exists()) {
						outputFile.getParentFile().mkdirs();
					}
					FileOutputStream out = new FileOutputStream(outputFile); // 输出到文件流
					ImageIO.write(tag, destFile.substring(destFile.lastIndexOf(".")+1), out);
					// 关闭输出流
					out.close();
					break;
				}
			}
			buf.clear();
			channel.close();
			raf.close();
			unmap(buf);
			result = true;
		}catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 解除map映射
	 * @param buffer
	 */
	private static <T> void unmap(final Object buffer) {
		AccessController.doPrivileged(new PrivilegedAction<T>() {
			public T run() {
				try {
					Method getCleanerMethod = buffer.getClass().getMethod(
							"cleaner", new Class[0]);
					getCleanerMethod.setAccessible(true);
					sun.misc.Cleaner cleaner = (sun.misc.Cleaner) getCleanerMethod
							.invoke(buffer, new Object[0]);
					cleaner.clean();
				} catch (Exception e) {
					e.printStackTrace();
				}
				return null;
			}
		});
	}

}
